//////////////////////////////////////////////////////////////////////////////////////////////////////
// 项目名   : ConditionVariable
// 文件名   : Queue.h
// 作者     : Aiye
// 日期     : 2025/9/23 12:01
// 邮箱     : 2878548868@qq.com
// 摘要     : 利用条件变量创建线程安全的队列
//////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef CONDITIONVARIABLE_QUEUE_H
#define CONDITIONVARIABLE_QUEUE_H
#include <condition_variable>
#include <deque>

/**
 * @brief 基于底层deque线程安全的容器
 * @tparam T 类型参数
 */
template<class T>
class ThreadSafeQueue
{
public:
    explicit ThreadSafeQueue(size_t n_capacity = 0)
        : _nCapacity(n_capacity){}

    ThreadSafeQueue(const ThreadSafeQueue& other) = delete;
    ThreadSafeQueue& operator=(const ThreadSafeQueue& other) = delete;

public:
    bool push(const T& value)
    {
        return enqueue_impl(value);
    }

    bool push(T&& value)
    {
        return enqueue_impl(std::move(value));
    }

    template<typename... Args>
    bool emplace(Args&&... args)
    {
        return enqueue_impl(T(std::forward<Args>(args)...));
    }

    /**
     * @brief 阻塞弹出头部元素
     * @param out 保存弹出结果
     * @return 若关闭且已空 false ；否则返回 true
     */
    bool wait_and_pop(T& out)
    {
        std::unique_lock lock{_mutex};
        _cvNotEmpty.wait(lock , [&]
        {
            return _bClosed || !_deque.empty();
        });

        if (_deque.empty())
        {
            return false;
        }

        out = std::move(_deque.front);
        _deque.pop_front();
        _cvNotFull.notify_one();
        return true;
    }

    /**
    * \brief 非阻塞尝试弹出头部
    */
    bool try_pop(T& out)
    {
        std::lock_guard<std::mutex> lock{_mutex};
        if (_deque.empty()) return false;
        out = std::move(_deque.front());
        _deque.pop_front();
        _cvNotFull.notify_one();
        return true;
    }

    /**
     * \brief 非阻塞从尾部弹出
     */
    bool try_pop_back(T& out)
    {
        std::lock_guard<std::mutex> lock{_mutex};
        if (_deque.empty()) return false;
        out = std::move(_deque.back());
        _deque.pop_back();
        _cvNotFull.notify_one();
        return true;
    }

    /**
     * \brief 关闭队列: 唤醒所有等待线程
     *  - 之后的入队返回 false
     *  - 之后的阻塞弹出若无数据返回 false
     */
    void close()
    {
        {
            std::lock_guard<std::mutex> lock{_mutex};
            _bClosed = true;
        }
        _cvNotEmpty.notify_all();
        _cvNotFull.notify_all();
    }

    /**
     * \brief 清空现有元素（不改变关闭状态）
     */
    void clear()
    {
        std::lock_guard<std::mutex> lock{_mutex};
        _deque.clear();
        _cvNotFull.notify_all();
    }

    /**
     * \brief 是否为空（快照）
     */
    bool empty() const
    {
        std::lock_guard<std::mutex> lock{_mutex};
        return _deque.empty();
    }

    /**
     * \brief 当前大小（快照）
     */
    size_t size() const
    {
        std::lock_guard<std::mutex> lock{_mutex};
        return _deque.size();
    }

    /**
     * \brief 是否已关闭
     */
    bool closed() const
    {
        std::lock_guard<std::mutex> lock{_mutex};
        return _bClosed;
    }

private:
    /**
     * @brief 入栈
     * @tparam U 独立参数模板，通过完美转发保持值类别，减少拷贝
     * @param value 入队的元素
     * @return 是否成功
     */
    template<typename U>
    bool enqueue_impl(U&& value)
    {
        std::unique_lock lock{_mutex};
        _cvNotFull.wait(lock ,[&]()
        {
            return _bClosed || _nCapacity == 0 || _deque.size() < _nCapacity;
        });

        if (_bClosed)
        {
            return false;
        }

        _deque.emplace_back(std::forward<U>(value)); // 完美转发
        _cvNotEmpty.notify_one(); // 唤醒一个等待取数据的线程
        return true;
    }

private:
    std::deque<T> _deque{}; // 底层容器
    std::condition_variable _cvNotEmpty{};
    std::condition_variable _cvNotFull{};
    size_t _nCapacity{};
    bool _bClosed{false};
    mutable std::mutex _mutex{};
};


#endif //CONDITIONVARIABLE_QUEUE_H